<template>
  <div
    v-if="!initializing"
    :style="'width: ' + (options.treeWidth || 200) + 'px'"
    class="cc-page-comp-tree cc-flex-column"
    v-collapse
    v-drag
  >
    <div class="tree-name" v-if="pageComp.treeName">{{pageComp.treeName}}</div>
    <div class="cc-page-comp-tree-header">
      <div class="tree-search">
        <el-input placeholder="搜索" v-model="filterText" clearable />
      </div>
      <div class="tree-button" v-if="pageComp.treeFormId">
        <el-tooltip
          placement="bottom"
          content="新增"
          :trigger="isMobile ? 'contextmenu' : 'hover'"
        >
          <cc-icon
            iconId="018dc9c3efed46e8b927"
            style="color: #333; font-size: 18px;"
            @click="addNode"
          />
        </el-tooltip>
      </div>
      <div v-else style="margin-right: 10px"></div>
    </div>
    <el-tree
      ref="tree"
      class="cc-page-comp-tree-main"
      node-key="id"
      :data="treeData"
      :props="treeProps"
      :default-expanded-keys="expandedData"
      :filter-node-method="filterNode"
      :highlight-current="true"
      :expand-on-click-node="true"
      @node-expand="nodeExpand"
      @node-collapse="nodeCollapse"
      @node-click="nodeClick"
    >
      <template v-slot="{ data }">
        <div class="node-item">
          <span class="node-label" :title="data.text"><span>{{data.text}}</span></span>
          <div class="node-button" v-if="pageComp.treeFormId">
            <el-dropdown trigger="hover" placement="bottom-start">
              <span class="node-button-item">
                <cc-icon iconId="018dca6283a1e534a046" style="color: #333" @click.stop />
              </span>
              <template #dropdown>
                <el-dropdown-menu>
                  <el-dropdown-item @click="addSubNode(data.data)">
                    <cc-icon iconId="018dc9c3efb74ac607cb" style="color: #67C23A; margin-right: 5px" />新增子级
                  </el-dropdown-item>
                  <el-dropdown-item @click="editNode(data.data)">
                    <cc-icon iconId="018dca6db20c6a3aaf68" style="color: #0085f6; margin-right: 5px" />修改
                  </el-dropdown-item>
                  <el-dropdown-item @click="deleteNode(data.data)">
                    <cc-icon iconId="018dc9c3efd3a0502886" style="color: #F56C6C; margin-right: 5px" />删除
                  </el-dropdown-item>
                </el-dropdown-menu>
              </template>
            </el-dropdown>
          </div>
        </div>
      </template>
    </el-tree>
  </div>

  <el-dialog
    v-model="dialogVisible"
    class="cc-page-comp-dialog"
    append-to-body
    destroy-on-close
    draggable
    :width="dialogWidth"
    :before-close="closeDialog"
    :close-on-click-modal="false"
    :fullscreen="dialogFullscreen"
  >
    <template #header>
      <div class="header" @dblclick="dialogFullscreen=!dialogFullscreen">
        <div class="title">{{dialogTitle}}</div>
        <div class="button">
          <cc-icon
            v-if="!dialogFullscreen"
            iconId="018dca8cad1b28075ecd"
            @click="dialogFullscreen=true"
            title="最大化"
          />
          <cc-icon
            v-if="dialogFullscreen"
            iconId="018dca8cad1b9b03c47f"
            @click="dialogFullscreen=false"
            title="缩小"
          />
        </div>
      </div>
    </template>
    <component
      ref="dialogCompRef"
      :is="dialogComponent"
      v-bind="dialogOptions"
    />
    <template #footer>
      <el-button
        type="info"
        @click="dialogVisible = false"
      >取消</el-button>
      <el-button
        type="primary"
        @click="submitDialogForm"
        :loading="dialogLoading"
      >提交</el-button>
    </template>
  </el-dialog>
</template>

<script setup>
import { ref, onMounted, markRaw, watch, inject, onUnmounted, nextTick } from 'vue';
import api from "@/http/api";
import Form from "@/codeless/view/form.vue";
import tool from "@/utils/tool";
import { ElMessage, ElMessageBox } from "element-plus";
import loading from "@/utils/loading";
import emitter from "@/utils/bus";
import { useDevice } from '@/utils/device';

const emit = defineEmits(['change']);
const props = defineProps({
  options: Object
});

const initializing = ref(true);
const { isMobile } = useDevice();
const pageComp = ref();
const tree = ref();
const filterText = ref([]);
const treeData = ref([]);
const treeProps = ref({
  children: 'children',
  label: 'text'
});
const expandedData = ref([]);
const currNode = ref(null);

const dialogTitle = ref('');
const dialogWidth = ref('');
const dialogFullscreen = ref(false);
const dialogVisible = ref(false);
const dialogLoading = ref(false);
const dialogComponent = ref();
const dialogOptions = ref({});
const dialogCompRef = ref();
const currMenuId = inject('menuId', '');

const filterNode = (value, data) => {
  if (!value) return true;
  return data.text.indexOf(value) >= 0;
};

const nodeExpand = (data) => {
  expandedData.value.push(data.id)
};

const nodeCollapse = (data) => {
  let index = expandedData.value.findIndex(item => item === data.id);
  if (index >= 0) {
    expandedData.value.splice(index, 1);
  }
};

const nodeClick = (node, treeNode) => {
  if (currNode.value && currNode.value.id === node.id) {
    treeNode.checked = !treeNode.checked;
  } else {
    treeNode.checked = true;
  }

  if (treeNode.checked) {
    currNode.value = node;
    emit('change', node);
  } else {
    tree.value.setCurrentKey(null);
    currNode.value = null;
    emit('change', {});
  }
};

const addNode = () => {
  dialogTitle.value = '新增';
  dialogWidth.value = '600px';
  dialogFullscreen.value = false;
  dialogOptions.value = {
    operate: '新增',
    dataFormId: pageComp.value.treeFormId,
    initData: {}
  };
  dialogComponent.value = markRaw(Form);
  dialogLoading.value = false;
  dialogVisible.value = true;
  dialogFullscreen.value = isMobile.value;
};

const closeDialog = (done) => {
  const viewer = document.getElementsByClassName('el-image-viewer__wrapper')[0];
  if(!viewer) {
    done();
  }
};

const addSubNode = (data) => {
  let initData = {};
  initData[pageComp.value.treeParentFieldName] = data[pageComp.value.treeNodeFieldName] || '';

  dialogTitle.value = '新增';
  dialogWidth.value = '600px';
  dialogFullscreen.value = false;
  dialogOptions.value = {
    operate: '新增',
    dataFormId: pageComp.value.treeFormId,
    initData: initData
  };
  dialogComponent.value = markRaw(Form);
  dialogLoading.value = false;
  dialogVisible.value = true;
  dialogFullscreen.value = isMobile.value;
};

const editNode = (data) => {
  dialogTitle.value = '编辑';
  dialogWidth.value = '600px';
  dialogFullscreen.value = false;
  dialogOptions.value = {
    operate: '编辑',
    dataFormId: pageComp.value.treeFormId,
    initData: tool.deepClone(data || {})
  };
  dialogComponent.value = markRaw(Form);
  dialogLoading.value = false;
  dialogVisible.value = true;
  dialogFullscreen.value = isMobile.value;
};

const deleteNode = (data) => {
  let prompt = '删除后数据无法恢复，请确认是否删除？'
  let url = '/codeless/'
    + currMenuId.value + '/'
    + pageComp.value.treeDataModelId + '/delete';
  if (pageComp.value.treeDeleteScriptId) {
    url = '/codeless/script/' + currMenuId.value + '/' + pageComp.value.treeDeleteScriptId + '/run';
  }
  ElMessageBox.confirm(prompt, '提示', {type: 'warning'}).then(() => {
    loading.showLoading();
    api.post(url, data).then(res => {
      ElMessage.success(res.message);
      loading.hideLoading();
      expandedData.value = [data[pageComp.value.treeParentFieldName] || '0'];
      loadTreeData();
    }).catch(e => {
      loading.hideLoading();
      console.log('操作失败！', e);
    });
  }).catch(() => {});
};

const submitDialogForm = () => {
  dialogCompRef.value.validate(valid => {
    if (valid) {
      let prompt = "请确认是否提交数据？";
      ElMessageBox.confirm(prompt, '提示', {type: 'info'}).then(() => {
        let url = '/codeless/'
          + currMenuId.value + '/'
          + pageComp.value.treeDataModelId + '/save';
        if (dialogTitle.value === '新增' && pageComp.value.treeAddScriptId) {
          url = '/codeless/script/' + currMenuId.value + '/' + pageComp.value.treeAddScriptId + '/run';
        } else if (dialogTitle.value === '编辑' && pageComp.value.treeEditScriptId) {
          url = '/codeless/script/' + currMenuId.value + '/' + pageComp.value.treeEditScriptId + '/run';
        }

        dialogLoading.value = true;
        let data = dialogCompRef.value.getData();
        api.post(url, dialogCompRef.value.getData()).then(res => {
          ElMessage.success(res.message);
          dialogLoading.value = false;
          dialogVisible.value = false;
          expandedData.value = [data[pageComp.value.treeParentFieldName] || '0'];
          loadTreeData();
        }).catch(e => {
          dialogLoading.value = false;
          console.log('操作失败！', e);
        });
      });
    }
  });
};

const loadTreeData = async() => {
  if (pageComp.value.showTree !== '1' || !pageComp.value.treeDataModelId) return;

  let url = '/codeless/page-comp/' + pageComp.value.id + '/tree';
  let res = await api.post(url);
  treeData.value = (res.data || []).children || [];
  if (expandedData.value.length === 0 && treeData.value.length > 0) {
    expandedData.value.push(treeData.value[0].id);
  }
};

const init = async() => {
  initializing.value = true;
  pageComp.value = props.options || {};

  if (pageComp.value.showTree !== '1' || !pageComp.value.treeDataModelId) return;
  await loadTreeData();
  await nextTick(() => initializing.value = false);
};

const refreshDataTimeout = ref();
const checkAndRefreshData = () => {
  let hash = window.location.hash;
  hash = "?" + (hash.indexOf("?") >= 0 ? hash.split("?", 2)[1] : hash);
  const hashParams = new URLSearchParams(hash);
  const menuId = hashParams.get('menuId');
  if (!currMenuId.value) {
    return;
  }

  if ((currMenuId.value || '') !== (menuId || '')) {
    if (refreshDataTimeout.value) {
      clearTimeout(refreshDataTimeout.value);
    }
    refreshDataTimeout.value = setTimeout(() => loadTreeData(), 500);
  }
};

watch(() => filterText.value, (val) => {
  tree.value.filter(val);
});

onMounted(async() => {
  await init();
  emitter.on("model.data.change." + pageComp.value.treeDataModelId, checkAndRefreshData);
});

onUnmounted(() => {
  emitter.off("model.data.change." + pageComp.value.treeDataModelId, checkAndRefreshData);
});

defineExpose({ loadTreeData })
</script>

<style scoped lang="scss">
.cc-page-comp-tree {
  flex-shrink: 0;
  width: 250px;
  display: flex;
  flex-direction: column;
  padding: 0 1px 1px 0;
  border-right: 1px solid var(--table-border-color);
  background-color: transparent;
  margin-right: 10px;
}
.tree-name {
  font-weight: 600;
  font-size: 16px;
  margin-bottom: 8px;
}
.cc-page-comp-tree-header {
  margin-bottom: 10px;
  display: flex;
  flex-shrink: 0;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  height: 40px;
  overflow: hidden;
  .tree-search {
    flex-grow: 1;
    width: 1px;
  }
  .tree-button {
    margin: 0 10px;
    height: 32px;
    width: 40px;
    border-radius: 5px;
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    border: none;
    cursor: pointer;
  }
  .tree-button:hover {
    background: #eaeaea;
    border: none;
  }
}

.cc-page-comp-tree-main {
  width: 100%;
  overflow: scroll;
  .node-item {
    display: flex;
    flex-direction: row;
    align-items: center;
    width: 100%;
    .node-label {
      flex-grow: 1;
      width: 1px;
      text-overflow: ellipsis;
      overflow: hidden;
      display: flex;
      line-height: 1;
      > span {
        width: 100%;
        text-overflow: ellipsis;
        overflow: hidden;
      }
    }
    .node-button {
      margin-right: 10px;
      display: flex;
      justify-content: center;
      align-items: center;
    }
    .node-button .node-button-item {
      height: 30px;
      width: 40px;
      display: flex;
      justify-content: center;
      align-items: center;
      border-radius: 5px;
    }
    .node-button .node-button-item:focus-visible {
      outline: unset;
    }
  }

  :deep(.el-tree-node__content) {
    height: 40px;
  }
  :deep(.el-tree-node:not(.is-current):focus>.el-tree-node__content) {
    background-color: unset!important;
  }
  :deep(.el-tree-node:focus>.el-tree-node__content) {
    background-color: unset!important;
  }
  :deep(.el-tree-node:focus>.el-tree-node__content:hover) {
    background-color: var(--el-color-primary-light-9) !important;
  }
  :deep(.el-tree-node.is-current:focus>.el-tree-node__content) {
    background-color: var(--el-color-primary-light-9) !important;
  }
  .node-item:hover {
    .node-button .node-button-item:hover {
      background: var(--el-color-primary-light-9) !important;
    }
  }
}
@media screen and (max-width: 1024px) {
  .tree-name {
    font-size: 14px;
    margin-bottom: 4px;
  }
  .cc-page-comp-tree-main {
    :deep(.el-tree-node__content) {
      height: 25px;
    }
    .node-button .node-button-item {
      height: 25px!important;
    }
  }
}
</style>